package org.opens.javaskill.design.apply;

import java.util.LinkedList;
import java.util.Random;
import java.util.stream.IntStream;

/**
 * 功能:
 * <p>称为保护暂停设计模式</p>
 * 说明:
 * <pre>
 *     1. 这种设计模式的核心是一个共享任务队列, 在旧任务未完成之前, 新任务到来需要先加入队列中, 等待就任务完成才会去执行新任务.
 * </pre>
 * @Date 2020/9/15 21:37
 * @Created by 99126
 */
public class GuardedSuspensionDemo {

    public static void main(String[] args) {
        RequestQueue requestQueue = new RequestQueue();

        ClientThread clientThread = new ClientThread(requestQueue, "s1");
        ServerThread serverThread = new ServerThread(requestQueue);

        serverThread.setDaemon(true);

        clientThread.start();
        serverThread.start();

        // 这种方式也可以关闭ServerThread, 但是不如设置为守护线程优雅
        /*while (clientThread.isAlive()) {
            try {
                Thread.sleep(50);
            } catch (InterruptedException e) {
                e.printStackTrace();
            }
        }
        serverThread.close();*/
    }

}

class RequestQueue {

    private final LinkedList<Request> queue = new LinkedList<>();

    public Request getRequest() {
        synchronized (queue) {
            while (queue.size() <= 0) {
                try {
                    queue.wait();
                } catch (InterruptedException e) {
                    e.printStackTrace();
                    return null;
                }
            }
            System.out.println("|get -> queue size " + queue.size());
            return queue.removeFirst();
        }
    }

    public void putRequest(Request request) {
        synchronized (queue) {
            queue.add(request);
            System.out.println("|put -> queue size " + queue.size());
            queue.notifyAll();
        }
    }

}

class Request {

    private String value;

    public Request(String value) {
        this.value = value;
    }

    public String getValue() {
        return value;
    }
}

class ClientThread extends Thread {

    private final RequestQueue requestQueue;

    private final Random random;

    private final String sendValue;

    public ClientThread(RequestQueue requestQueue, String sendValue) {
        this.requestQueue = requestQueue;
        this.random = new Random(System.currentTimeMillis());
        this.sendValue = sendValue;
    }

    @Override
    public void run() {
        IntStream.rangeClosed(0, 10).forEach(i -> {
            requestQueue.putRequest(new Request(sendValue));
            System.out.println("client -> request " + sendValue);
            try {
                Thread.sleep(random.nextInt(1000));
            } catch (InterruptedException e) {
                e.printStackTrace();
            }
        });
    }
}

class ServerThread extends Thread {

    private final RequestQueue requestQueue;

    private final Random random;

    private volatile boolean exitFlag = false;

    public ServerThread(RequestQueue requestQueue) {
        this.requestQueue = requestQueue;
        this.random = new Random(System.currentTimeMillis());
    }

    @Override
    public void run() {
        while (!exitFlag) {
            Request request = requestQueue.getRequest();
            if (request == null) {
                System.out.println("server => request is null");
                continue;
            }
            System.out.println("server -> " + request.getValue());
            try {
                Thread.sleep(random.nextInt(1000));
            } catch (InterruptedException e) {
                e.printStackTrace();
                break;
            }
        }
    }

    public void close() {
        this.exitFlag = true;
        this.interrupt();
    }
}